package cn.jonay.pdmreader.ui;


import cn.jonay.pdmreader.core.meta.*;
import cn.jonay.pdmreader.core.reader.PdmReader;
import cn.jonay.pdmreader.core.render.PdmRender;
import cn.jonay.pdmreader.ui.model.FileType;
import cn.jonay.pdmreader.ui.model.PdmTableModel;
import cn.jonay.pdmreader.ui.model.ReadonlyTableModel;

import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.*;
import java.io.File;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 说明
 *
 * @author zhaozhiguo
 * @version 1.0
 * @date 2021/2/8 13:29
 */
public class PdmView extends JFrame {

    private JTable tableGrid;
    private JTable indexGrid;
    private JTree tree;
    private File latestPath;
    private Pdm pdm;
    private PdmRender render = new PdmRender();

    public PdmView() {
        init();
    }

    private void init() {
        setTitle("PDM Reader");
        setIconImage(getToolkit().getImage(PdmView.class.getResource("/static/pdm.jpg")));
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setExtendedState(Frame.MAXIMIZED_BOTH);
        this.setSize(1024, 768);
        this.setLocationRelativeTo(null);

        JScrollPane leftPanel = new JScrollPane();
        tree = new JTree();
        tree.setModel(new DefaultTreeModel(null));
        tree.addTreeSelectionListener(this::treeSelectActionPerformed);
        leftPanel.setViewportView(tree);

        JScrollPane tablePanel = new JScrollPane();
        tableGrid = new JTable();
        tableGrid.setModel(new DefaultTableModel());
        tablePanel.setViewportView(tableGrid);

        JScrollPane indexPanel = new JScrollPane();
        indexGrid = new JTable();
        indexGrid.setModel(new DefaultTableModel());
        indexPanel.setViewportView(indexGrid);

        JTabbedPane rightPanel = new JTabbedPane();
        rightPanel.setTabPlacement(SwingConstants.BOTTOM);
        rightPanel.addTab("表结构", tablePanel);
        rightPanel.addTab("索引", indexPanel);

        //主面板
        JSplitPane mainPanel = new JSplitPane();
        mainPanel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                int mWidth = Math.max(200, (int) (getWidth() * 0.25));
                mainPanel.setDividerLocation(mWidth);
            }
        });
        this.getRootPane().registerKeyboardAction(this::menuActionPerformed, "Paste", KeyStroke.getKeyStroke("control V"), JComponent.WHEN_FOCUSED);
        mainPanel.setLeftComponent(leftPanel);
        mainPanel.setRightComponent(rightPanel);
        new DropTarget(mainPanel, DnDConstants.ACTION_COPY_OR_MOVE, new DropTargetAdapter() {
            @Override
            public void drop(DropTargetDropEvent dtde) {
                boolean isAccept = false;
                if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                    // 接收拖拽目标数据
                    dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                    isAccept = true;
                    processFileObject(dtde.getTransferable());
                }
                // 如果此次拖拽的数据是被接受的, 则必须设置拖拽完成（否则可能会看到拖拽目标返回原位置, 造成视觉上以为是不支持拖拽的错误效果）
                if (isAccept) {
                    dtde.dropComplete(true);
                }
            }
        }, true);
        setContentPane(mainPanel);

        JMenu menuFile = new JMenu();
        menuFile.setText("文件(F)");
        menuFile.setMnemonic(KeyEvent.VK_F);
        String[][] menuFileItems = new String[][]{{"打开", "control O"}, {"关闭", "control W"}, {"退出", "control Q"}};
        for (String[] menuFileItem : menuFileItems) {
            JMenuItem item = new JMenuItem();
            item.setText(menuFileItem[0]);
            item.setAccelerator(KeyStroke.getKeyStroke(menuFileItem[1]));
            item.addActionListener(this::menuActionPerformed);
            menuFile.add(item);
        }

        JMenu menuExport = new JMenu();
        menuExport.setText("导出(P)");
        menuExport.setMnemonic(KeyEvent.VK_P);
        String[] exportTypes = new String[]{"导出Markdown格式", "导出HTML格式", "导出PDF格式"};
        for (String exportType : exportTypes) {
            JMenuItem menuItem = new JMenuItem();
            menuItem.setText(exportType);
            menuItem.addActionListener(this::menuActionPerformed);
            menuExport.add(menuItem);
        }

        JMenu menuHelp = new JMenu();
        menuHelp.setText("帮助(F1)");
        menuHelp.setMnemonic(KeyEvent.VK_F1);
        JMenuItem menuAbout = new JMenuItem();
        menuAbout.setText("关于");
        menuAbout.setAccelerator(KeyStroke.getKeyStroke("control Enter"));
        menuAbout.addActionListener(this::menuActionPerformed);
        menuHelp.add(menuAbout);

        JMenuBar menuBar = new JMenuBar();
        menuBar.add(menuFile);
        menuBar.add(menuExport);
        menuBar.add(menuHelp);

        setJMenuBar(menuBar);

        pack();
    }

    private void menuActionPerformed(ActionEvent event) {
        switch (event.getActionCommand()) {
            case "打开":
                JFileChooser jfc = new JFileChooser(latestPath);
                jfc.setFileFilter(new FileNameExtensionFilter("PDM文件(*.pdm)", "pdm"));

                jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);

                if (JFileChooser.APPROVE_OPTION == jfc.showOpenDialog(this)) {
                    File file = jfc.getSelectedFile();
                    latestPath = file.getParentFile();
                    doReadPdmFile(file);
                }
                break;
            case "关闭":
                tree.setModel(new DefaultTreeModel(null));
                tableGrid.setModel(new DefaultTableModel());
                indexGrid.setModel(new DefaultTableModel());
                pdm = null;
                break;
            case "退出":
                System.exit(0);
                break;
            case "关于":
                JOptionPane.showMessageDialog(null, "Author: jonay\nVersion: 1.0.0\nEmail: jonay_angel@163.com", "关于", JOptionPane.INFORMATION_MESSAGE);
                break;
            case "Paste":
                processFileObject(this.getToolkit().getSystemClipboard().getContents(null));
                break;
            case "导出Markdown格式":
                exportFile(FileType.Markdown, "Markdown文档(*.md)", "md");
                break;
            case "导出PDF格式":
                exportFile(FileType.Pdf, "PDF文档(*.pdf)", "pdf");
                break;
            case "导出HTML格式":
                exportFile(FileType.Html, "HTML文档(*.html)", "html", "html");
                break;
            default:
                JOptionPane.showMessageDialog(null, "待完成", "关于", JOptionPane.WARNING_MESSAGE);
                break;
        }
    }

    private void exportFile(FileType fileType, String description, String... extensions) {
        if (pdm == null) {
            return;
        }
        JFileChooser dialog = new JFileChooser();
        dialog.setDialogTitle("导出");
        dialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
        dialog.setDialogType(JFileChooser.SAVE_DIALOG);
        dialog.setFileFilter(new FileNameExtensionFilter(description, extensions));
        int result = dialog.showSaveDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File file = dialog.getSelectedFile();
            render.render(fileType, pdm, file);
            JOptionPane.showMessageDialog(null, "导出成功！", "导出", JOptionPane.INFORMATION_MESSAGE);

        }
    }

    private void processFileObject(Transferable transferable) {
        try {
            java.util.List<File> files = (java.util.List<File>) transferable.getTransferData(DataFlavor.javaFileListFlavor);
            if (files != null) {
                Optional<File> file = files.stream().filter(f -> f.getName().toLowerCase().endsWith(".pdm")).findFirst();
                file.ifPresent(this::doReadPdmFile);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void doReadPdmFile(File file) {
        Pdm pdm = PdmReader.read(file).doParse();
        DefaultMutableTreeNode root = new DefaultMutableTreeNode(pdm.getName());
        for (Table t : pdm.getTables()) {
            root.add(new PdmTableModel(t));
        }
        tree.setModel(new DefaultTreeModel(root));
        this.pdm = pdm;
    }

    private void treeSelectActionPerformed(TreeSelectionEvent event) {
        fillTable(null);
        fillIndex(null);
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        if (node == null || !node.isLeaf()) {
            return;
        }
        Object object = node.getUserObject();
        Table table = (Table) object;
        fillTable(table);
        fillIndex(table);

    }

    private void fillTable(Table table) {
        String[] columnNames = {"名称", "CODE", "数据类型", "是否主键", "是否可空", "备注"};

        Object[][] data = null;
        if (table != null) {
            java.util.List<Column> cols = table.getColumns();
            data = cols.stream().map(col -> new Object[]{
                    col.getName(),
                    col.getCode(),
                    col.getDataType(),
                    col.isPk() ? "√" : "",
                    col.isNullable() ? "√" : "",
                    col.getComment()}).collect(Collectors.toList()).toArray(new Object[][]{});
        }
        tableGrid.setModel(new ReadonlyTableModel(data, columnNames));
        tableGrid.setRowSorter(new TableRowSorter<>(tableGrid.getModel()));
    }

    private void fillIndex(Table table) {
        String[] columnNames = {"名称", "CODE", "是否唯一索引", "索引字段", "备注"};
        Object[][] data = null;
        if (table != null) {
            java.util.List<Index> indexes = table.getIndexes();
            data = indexes.stream().map(idx -> new Object[]{
                    idx.getName(),
                    idx.getCode(),
                    idx.isUnique() ? "√" : "",
                    idx.getColumns().stream().collect(Collectors.joining(",")),
                    idx.getComment()}).collect(Collectors.toList()).toArray(new Object[][]{});
        }
        indexGrid.setModel(new ReadonlyTableModel(data, columnNames));
    }

    public static void main(String args[]) {
        try {
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception ex) {
        }
        EventQueue.invokeLater(() -> new PdmView().setVisible(true));
    }


}
